//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

import { makeAutoObservable, runInAction } from 'mobx';
import type { ReactFlowInstance } from 'reactflow';
import type { ViewInfo, NodeInfo, EdgeInfo, EdgeInfoKey } from "@/api/project_dataview";
import { list_node, list_edge, get_view, get_node, get_edge } from "@/api/project_dataview"
import { get_session } from '@/api/user';
import { request } from '@/utils/request';
import { get_project, list_tag, TAG_SCOPRE_ALL, type ProjectInfo, type TagInfo } from '@/api/project';
import { type MemberInfo, list_member } from '@/api/project_member';

export class ProjectDataViewStore {
    constructor() {
        makeAutoObservable(this);
    }

    private _dataViewId = "";
    private _projectId = "";
    private _projectInfo: ProjectInfo | null = null;
    private _tagList: TagInfo[] = [];
    private _myUserId = "";
    private _memberList: MemberInfo[] = [];

    private _flowInstance: ReactFlowInstance | null = null;
    private _viewInfo: ViewInfo | null = null;
    private _nodeList: NodeInfo[] = [];
    private _edgeList: EdgeInfo[] = [];

    get dataViewId() {
        return this._dataViewId;
    }

    set dataViewId(val: string) {
        runInAction(() => {
            this._dataViewId = val;
        });
    }

    get projectId() {
        return this._projectId;
    }

    get projectInfo() {
        return this._projectInfo;
    }

    get tagList() {
        return this._tagList;
    }

    get myUserId() {
        return this._myUserId;
    }

    set myUserId(val: string) {
        runInAction(() => {
            this._myUserId = val;
        });
    }

    get myUser() {
        return this._memberList.find(item => item.member_user_id == this._myUserId);
    }

    get memberList() {
        return this._memberList;
    }

    set projectId(val: string) {
        runInAction(() => {
            this._projectId = val;
        });
    }

    get flowInstance(): ReactFlowInstance | null {
        return this._flowInstance;
    }

    get viewInfo() {
        return this._viewInfo;
    }

    set flowInstance(val: ReactFlowInstance) {
        runInAction(() => {
            this._flowInstance = val;
        });
    }

    get nodeList() {
        return this._nodeList;
    }

    get edgeList() {
        return this._edgeList;
    }

    async loadProject() {
        const sessionId = await get_session();
        const res = await request(get_project(sessionId, this._projectId));
        runInAction(() => {
            this._projectInfo = res.info;
        });
    }

    async loadMemberList() {
        const sessionId = await get_session();
        const res = await request(list_member(sessionId, this._projectId, false, []));
        runInAction(() => {
            this._memberList = res.member_list;
        });
    }

    async loadTagList() {
        const sessionId = await get_session();
        const res = await request(list_tag({
            session_id: sessionId,
            project_id: this._projectId,
            tag_scope_type: TAG_SCOPRE_ALL,
        }));
        runInAction(() => {
            this._tagList = res.tag_info_list;
        });
    }

    async loadViewInfo() {
        const sessionId = await get_session();
        const res = await request(get_view({
            session_id: sessionId,
            project_id: this._projectId,
            view_id: this._dataViewId,
        }));
        runInAction(() => {
            this._viewInfo = res.view;
        });
    }

    async loadNodeList() {
        const sessionId = await get_session();
        const res = await request(list_node({
            session_id: sessionId,
            project_id: this._projectId,
            view_id: this._dataViewId,
        }));
        runInAction(() => {
            this._nodeList = res.node_list;
        });
    }

    getNode(nodeId: string): NodeInfo | undefined {
        return this._nodeList.find(item => item.node_id == nodeId);
    }

    async loadEdgeList() {
        const sessionId = await get_session();
        const res = await request(list_edge({
            session_id: sessionId,
            project_id: this._projectId,
            view_id: this._dataViewId,
        }));
        runInAction(() => {
            this._edgeList = res.edge_list;
        });
    }

    async onUpdateNode(nodeId: string) {
        const sessionId = await get_session();
        const res = await request(get_node({
            session_id: sessionId,
            project_id: this._projectId,
            view_id: this._dataViewId,
            node_id: nodeId,
        }));
        const tmpList = this._nodeList.slice();
        const index = tmpList.findIndex(item => item.node_id == nodeId);
        if (index == -1) {
            tmpList.push(res.node);
        } else {
            tmpList[index] = res.node;
        }
        runInAction(() => {
            this._nodeList = tmpList;
        });
    };

    async onRemoveNode(nodeId: string) {
        const tmpNodeList = this._nodeList.filter(item => item.node_id != nodeId);
        const tmpEdgeList = this._edgeList.filter(item => item.edge_key.from_node_id != nodeId && item.edge_key.to_node_id != nodeId);
        runInAction(() => {
            this._nodeList = tmpNodeList;
            this._edgeList = tmpEdgeList;
        });
    }

    async updateNodePosition(nodeId: string, x: number, y: number) {
        const tmpList = this._nodeList.slice();
        const index = tmpList.findIndex(item => item.node_id == nodeId);
        if (index != -1) {
            tmpList[index].x = x;
            tmpList[index].y = y;
            runInAction(() => {
                this._nodeList = tmpList;
            });
        }
    }

    async updateNodeSize(nodeId: string, w: number, h: number) {
        const tmpList = this._nodeList.slice();
        const index = tmpList.findIndex(item => item.node_id == nodeId);
        if (index != -1) {
            tmpList[index].w = w;
            tmpList[index].h = h;
            runInAction(() => {
                this._nodeList = tmpList;
            });
        }
    }

    async onUpdateEdge(edgeKey: EdgeInfoKey) {
        const sessionId = await get_session();
        const res = await request(get_edge({
            session_id: sessionId,
            project_id: this._projectId,
            view_id: this._dataViewId,
            edge_key: edgeKey,
        }));
        const tmpList = this._edgeList.slice();
        const index = tmpList.findIndex(item => item.edge_key.from_node_id == edgeKey.from_node_id && item.edge_key.from_handle_id == edgeKey.from_handle_id &&
            item.edge_key.to_node_id == edgeKey.to_node_id && item.edge_key.to_handle_id == edgeKey.to_handle_id);
        if (index == -1) {
            tmpList.push(res.edge);
        } else {
            tmpList[index] = res.edge;
        }
        runInAction(() => {
            this._edgeList = tmpList;
        });
    }

    async onRemoveEdge(edgeKey: EdgeInfoKey) {
        const tmpList = this._edgeList.filter(item => !(item.edge_key.from_node_id == edgeKey.from_node_id &&
            item.edge_key.from_handle_id == edgeKey.from_handle_id && item.edge_key.to_node_id == edgeKey.to_node_id && item.edge_key.to_handle_id == edgeKey.to_handle_id));
        runInAction(() => {
            this._edgeList = tmpList;
        });
    }
}